Skip to content

[FEATURE] Add filter_link_idx to contact sensors.#2772

Open
jsw7460 wants to merge 4 commits into
Genesis-Embodied-AI:mainfrom
jsw7460:feature/contact-force-filter-link-idx
Open

[FEATURE] Add filter_link_idx to contact sensors.#2772
jsw7460 wants to merge 4 commits into
Genesis-Embodied-AI:mainfrom
jsw7460:feature/contact-force-filter-link-idx

Conversation

@jsw7460

@jsw7460 jsw7460 commented May 12, 2026

Copy link
Copy Markdown

ContactForceSensor now accepts filter_link_idx, mirroring ContactSensor: contacts with the sensor link whose other participant is one of the listed links are excluded from the reported force. The filter is applied on both ground-truth-update paths; the vectorized zerocopy path and the _kernel_get_contacts_forces kernel.
Adds test_contact_force_sensor_filter_link_idx.

Description

ContactForceSensor now accepts filter_link_idx (default ()), mirroring
ContactSensor from #2655: contacts with the sensor link whose other
participant is one of the listed links are excluded from the reported force.

- `_kernel_get_contacts_forces` (the kernel fallback): takes
  `filter_links_idx` and skips a contact for a sensor when the counterpart
  is in that sensor's filter list;
- `filtered_sensor_idx` gates the comparison so sensors without a filter
  keep the cheap path (same optimisation as `ContactSensor`).

Related Issue

Resolves #2771

Motivation and Context

ContactSensor already filters its boolean by counterpart link, but ContactForceSensor only reported the total contact force on the link, with no way to scope it (e.g. "force on a foot from the ground, excluding self-contact").

How Has This Been / Can This Be Tested?

  pytest tests/test_sensors.py::test_contact_force_sensor_filter_link_idx tests/test_sensors.py::test_contact_sensor_filter_link_idx

test_contact_force_sensor_filter_link_idx puts a box on the floor (env 0) / a box on the floor with another box stacked on top (env 1), with two ContactForce sensors on the bottom box — one plain, one with filter_link_idx (floor.link_start,). It asserts the filtered sensor reads ~0 in env 0 and reads only the top box's downward push in env 1, while the unfiltered sensor reads the net contact force in both.

Checklist:

  • I read the CONTRIBUTING document.
  • I followed the Submitting Code Changes section of CONTRIBUTING document.
  • I tagged the title correctly (including BUG FIX/FEATURE/MISC/BREAKING)
  • I updated the documentation accordingly or no change is needed.
  • [ x] I tested my changes and added instructions on how to test it for reviewers.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@Milotrince

Copy link
Copy Markdown
Member

This feature has already been implemented by #2655 .

@jsw7460

jsw7460 commented May 12, 2026

Copy link
Copy Markdown
Author

@Milotrince
Hi, thank you for #2655 !
But #2655 added filter_link_idx only to gs.sensors.Contact (the boolean contact sensor), not to gs.sensors.ContactForce (the force-vector sensor).

What I'm after here is a ContactForce sensor that sums only the force from contacts with a given subset of links — e.g. "force on a foot from the ground, excluding self-contact" — which
isn't possible today since ContactForce reports the total contact force on the link.

@Milotrince Milotrince force-pushed the feature/contact-force-filter-link-idx branch from d42940d to 6f1b2ea Compare July 8, 2026 00:26
@Milotrince Milotrince changed the title [FEATURE] Add filter_link_idx to ContactForceSensor. [FEATURE] Add filter_link_idx to contact sensors. Jul 8, 2026
@Milotrince

Copy link
Copy Markdown
Member

I rebased your branch and updated to extend the filtering to ContactDepthProbe and KinematicTaxel as well as ContactProbe!

@Milotrince Milotrince force-pushed the feature/contact-force-filter-link-idx branch from 6f1b2ea to 1358dea Compare July 8, 2026 01:29
@Milotrince Milotrince added the ready for review First pass review complete and ready for final review and merge. label Jul 8, 2026
Milotrince
Milotrince previously approved these changes Jul 8, 2026
ContactForceSensor now accepts filter_link_idx, mirroring ContactSensor:
contacts with the sensor link whose other participant is one of the
listed links are excluded from the reported force. The filter is applied
on both ground-truth-update paths -- the vectorized zerocopy path (same
4D contact-vs-filter broadcast as ContactSensor, applied to the per-side
contact masks before they are aggregated) and the
_kernel_get_contacts_forces kernel (a small per-contact loop over the
sensor's filter list). As in ContactSensor, filtered_sensor_idx gates
the more expensive comparison so sensors without a filter keep the cheap
path. Adds test_contact_force_sensor_filter_link_idx.
@Milotrince Milotrince force-pushed the feature/contact-force-filter-link-idx branch from 6df1f03 to 82e30bd Compare July 10, 2026 23:29
ContactProbe, ContactDepthProbe, and KinematicTaxel now accept
filter_link_idx, mirroring the Contact/ContactForce semantics: a contact
with the sensor link is dropped when its counterpart link is in the
filter list. The three share the counterpart check via a
_func_link_is_filtered device helper threaded into both contact-depth
query funcs and their kernels, and a SolverContactProbeSensorOptionsMixin
so the point-cloud tactile sensors (Elastomer/Proximity), which sample a
point cloud rather than solver contacts, do not expose the option.

Consolidate the existing contact-force filtering while here:
- the kernel now uses the shared _func_link_is_filtered helper instead of
  open-coding the per-contact filter flags;
- the zerocopy filter masking (identical in Contact and ContactForce) is
  factored into _apply_counterpart_filter;
- the build-time padding is factored into misc.append_filter_links_idx
  (used by all five sensors) and the range validation into
  options._validate_filter_link_idx.

The filter table keeps at least one column so the no-filter case is still
a valid kernel argument. Adds test_contact_probe_sensor_filter_link_idx.
"apply ... filter" didn't convey what the function does. It clears mask
entries for contacts whose counterpart link is filtered out, matching the
wording already used for this behavior elsewhere (e.g. the test docstring
"drops contacts whose counterpart is filtered"). The self-describing name
replaces the docstring, which is dropped.
…SensorOptionsMixin

The mixin's only contribution over TactileProbeSensorOptionsMixin is
filter_link_idx (+ its validation); nothing "solver-contact" specific lives in
it - that's in the sensor implementations. Name it for what it adds: the
subset of tactile probes that support counterpart-link contact filtering. The
point-cloud probes (Elastomer/Proximity) intentionally stay unfiltered - they
already scope via track_link_idx (an allowlist), the dual of filter_link_idx.
@Milotrince Milotrince force-pushed the feature/contact-force-filter-link-idx branch from 82e30bd to 37e6118 Compare July 11, 2026 00:06
@github-actions

Copy link
Copy Markdown

⚠️ Abnormal Benchmark Result Detected ➡️ Report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review First pass review complete and ready for final review and merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add filter_link_idx to ContactForceSensor

2 participants